package Game;

import com.jme.app.AbstractGame.ConfigShowMode;
import com.jme.bounding.BoundingBox;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;
import java.awt.Toolkit;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

class Game implements KeyListener {
    private int myIndex;
    private Receiver receiver;
    private Sender sender;
    private volatile Packet sPacket;
    private Thread actions;
    private int frame = 33;
    private int freq = 3;                                               //how often per frame do I send the coords and direction...
    private ArrayList<FPSPlayer> players = new ArrayList<FPSPlayer>();

    public Game(int myIndex, Client[] clients) {
        this.myIndex = myIndex;

        receiver = new Receiver();
        sender = new Sender();

        for (int i = 0; i < clients.length; i++){
            if (i != myIndex){
                receiver.addClient(clients[i]);
                Node n = new Node();
                Box box = new Box(String.valueOf(i), new Vector3f(0, 0, 0), 5, 5, 5);
                box.setModelBound(new BoundingBox());
                n.attachChild(box);
                FPSPlayer fpsp = new FPSPlayer(String.valueOf(i), n);
                fpsp.randomPosition();
                players.add(fpsp);
                
            }
            if (i != myIndex+1){
                sender.addClient(clients[i]);
            }
        }

        receiver.start();
        sender.start();

        Thread jME = new Thread(){
            @Override
            public void run() {
                JMEGraphic app = new JMEGraphic(players);
                app.setConfigShowMode(ConfigShowMode.NeverShow, JMEGraphic.class
                        .getClassLoader().getResource(
                                "jmetest/data/images/FlagRush.png"));
                app.start();
            }
        };

        jME.start();

        JFrame input = new JFrame();
        input.setSize(Toolkit.getDefaultToolkit().getScreenSize().width, 80);
        input.setLocation(0, Toolkit.getDefaultToolkit().getScreenSize().height-input.getHeight());
        input.setAlwaysOnTop(true);
        input.addKeyListener(this);
        input.setVisible(true);
        JFrame.getWindows()[0].dispose();
        
        final int index = myIndex;

        createNewPacket();
        actions = new Thread() {

            @Override
            public void run() {
                while(true){
                    for(int i = 0; i < freq; i++){
                        try {
                            sPacket.addPosition(new NodePosition(players.get(index).getPosition(), new float[]{0, 0, 0}));
                            //sPacket.addPosition(new NodePosition(new float[]{0, 0, 0}, new float[]{0, 0, 0}));
                        }
                        catch (PacketAlreadyPackedException ex){
                            ex.printStackTrace();
                        }
                        try {
                            Thread.sleep(frame/freq);
                        }
                        catch (InterruptedException ex){
                            ex.printStackTrace();
                        }
                    }
                    sPacket.pack();
                    sender.sendPacket(sPacket);
                    //System.out.println(sPacket.toString());
                    createNewPacket();
                }
            }
        };
        actions.start();

    }

    public void handlePacket(Packet rPacket){
        if (rPacket.isActionRelevant()){
            long[] delay = new long[rPacket.getKeySize()];
            delay[0] = rPacket.readKeyStroke(0).getTimestamp();
            for (int i = 1; i < rPacket.getKeySize(); i++){
                delay[i] = rPacket.readKeyStroke(i).getTimestamp()-delay[i-1];
            }
            executeKeyStrokes(rPacket, delay);
        }
        if (rPacket.getIndex() != myIndex){
            executePosition(rPacket);
        }
    }

    private void executePosition(final Packet rPacket){
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < rPacket.getSpotSize(); i++){
                    players.get(rPacket.getIndex()).setPosition(rPacket.readPosition(i));
                    try {
                        Thread.sleep(frame/rPacket.getSpotSize());
                    }
                    catch (InterruptedException ex){
                        ex.printStackTrace();
                    }
                }
            }
        }.start();
    }

    private void executeKeyStrokes(final Packet rPacket, final long[] delay){
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < rPacket.getKeySize(); i++){
                    try {
                        Thread.sleep(delay[i]);
                    }
                    catch (InterruptedException ex){
                        ex.printStackTrace();
                    }
                    //myNode.action(receive_packet.readKeyStroke(i).getKeycode());
                    System.out.println((char) rPacket.readKeyStroke(i).getKeycode());
                }
            }
        }.start();
    }

    private void createNewPacket(){
        sPacket = null;
        sPacket = new Packet(myIndex, freq);
    }

    public void keyPressed(KeyEvent e) {
        try {
            sPacket.addKeyStroke(new KeyStroke(e.getKeyCode()));
        }
        catch (PacketAlreadyPackedException ex){
            ex.printStackTrace();
        }
    }

    // <editor-fold defaultstate="collapsed" desc="Unused KeyListenerMethods">
    public void keyTyped(KeyEvent e) {
    }

    public void keyReleased(KeyEvent e) {

    }// </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Class Sender">
    class Sender {
        private Client[] sender_clients;
        private Vector sender_clients_vector;
        private boolean classic_init;

        public Sender(Client[] sender_clients) {
            this.sender_clients = sender_clients;
            classic_init = false;
        }

        public Sender(){
            classic_init = true;
            sender_clients_vector = new Vector();
        }

        public void addClient(Client client){
            sender_clients_vector.addElement(client);
        }

        public void start(){
            if (classic_init){
                sender_clients = new Client[sender_clients_vector.size()];
                for (int i = 0; i < sender_clients_vector.size(); i++){
                    sender_clients[i] = (Client) sender_clients_vector.elementAt(i);
                }
            }
        }

        // <editor-fold defaultstate="collapsed" desc="Send">
        public void sendInt(int value) {
            sendLine(String.valueOf(value));
        }

        public void sendLine(String line) {
            for (int i = 0; i < sender_clients.length; i++) {
                sender_clients[i].sendLine(line);
            }
        }

        public void sendResponse() {
            sendLine("Response");
        }

        public void sendPacket(Packet packet) {
            for (int i = 0; i < sender_clients.length; i++) {
                sender_clients[i].sendPacket(packet);
            }
        }// </editor-fold>
    }// </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Class Receiver">
    class Receiver {

        private Client[] receiver_clients;
        private Vector receiver_clients_vector;
        private boolean classic_init;

        public Receiver(Client[] receiver_clients) {
            this.receiver_clients = receiver_clients;
            classic_init = false;
        }

        public Receiver(){
            classic_init = true;
            receiver_clients_vector = new Vector();
        }

        public void addClient(Client client){
            receiver_clients_vector.addElement(client);
        }

        public void start(){
            if (classic_init){
                receiver_clients = new Client[receiver_clients_vector.size()];
                for (int i = 0; i < receiver_clients_vector.size(); i++){
                    receiver_clients[i] = (Client) receiver_clients_vector.elementAt(i);
                }
            }
            for (int i = 0; i < receiver_clients.length; i++){
                receiveFromClient(i).start();
            }
        }

        private Thread receiveFromClient(final int index){

            return new Thread() {
                @Override
                public void run() {
                    while (true){
                        handlePacket(receivePacketWait(index));
                    }
                }
            };
        }

        // <editor-fold defaultstate="collapsed" desc="Receive">
        public int receiveIntWait(int index) {
            return receiver_clients[index].receiveIntWait();
        }

        public String receiveLineWait(int index) {
            return receiver_clients[index].receiveLineWait();
        }

        public void requestResponse(int index) {
            receiver_clients[index].requestResponse();
        }

        public Packet receivePacketWait(int index) {
            Packet packet = new Packet(receiveLineWait(index));
            return packet;
        }// </editor-fold>
    }// </editor-fold>
}




